package com.huas.service.serviceimpl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.lang.tree.TreeNode;
import com.github.pagehelper.Page;
import com.github.pagehelper.PageHelper;
import com.huas.common.PageResult;
import com.huas.constant.MessageConstant;
import com.huas.dto.CommentDTO;
import com.huas.entity.Comment;
import com.huas.exception.BaseException;
import com.huas.mapper.CommentMapper;
import com.huas.mapper.UserMapper;
import com.huas.service.CommentService;
import com.huas.utils.SecurityUtils;
import com.huas.vo.CommentVO;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.StringUtils;

import javax.annotation.Resource;
import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.function.Function;

@Service
public class CommentServiceImpl implements CommentService {
    @Resource
    CommentMapper commentMapper;
    @Resource
    UserMapper userMapper;

    /**
     * 后端显示
     * 条件分页评论列表
     */
    @Override
    public PageResult pageAll(Integer page, Integer pageSize,Character type, Integer titleId) {
        //设置分页参数
        PageHelper.startPage(page,pageSize);
        //查询分页结果集合(对所有评论数量进行分页)
        Page<Comment> p = commentMapper.pageAll(type,titleId);
        List<CommentVO> commentVOList = getCommentVOList(p.getResult());
        return new PageResult(p.getTotal(),commentVOList);
    }
    /**
     * 前端显示
     * 分页查询评论列表（树形结构）
     */
    @Override
    @Transactional
    public PageResult getCommentList(Character type,Integer titleId, Integer page, Integer pageSize) {
        //设置分页参数
        PageHelper.startPage(page,pageSize);
        //查询分页结果集合(只对根评论数量进行分页)
        Page<Comment> p =  commentMapper.page(type,titleId);
        List<CommentVO> commentVOList = getCommentVOList(p.getResult());
        //获取子评论并赋值children属性
        getChildren(commentVOList);
        //返回分页结果
        return new PageResult(p.getTotal(),commentVOList);
        /** HuTools工具包TreeUtils生成树列表
         //将查询到的Comment集合转换成CommentVO集合
         List<CommentVO> commentVOlist =  getCommentVOList(commentMapper.getCommentList(articleId));
         //转换成树形集合
         List<TreeNode<Integer>> collect = commentVOlist.stream().map(getNodeFunction()).collect(Collectors.toList());
         List<Tree<Integer>> treeList = TreeUtil.build(collect, -1);
         return new PageResult(p.getTotal(), treeList);
         */
    }

    /**
     * 发表评论
     */
    @Override
    @Transactional
    public void addComment(CommentDTO commentDTO) {
        Comment comment = BeanUtil.copyProperties(commentDTO, Comment.class);
        //判断内容不能为空（添加敏感词等）
        if(!StringUtils.hasText(comment.getContent())){
            throw new BaseException(MessageConstant.COMMENT_CONTENT_NULL);
        }
        //补充基础数据(后续可以公共字段自动填充)
        comment.setCreateBy(SecurityUtils.getUserId());
        comment.setCreateTime(LocalDateTime.now());
        commentMapper.reset();
        commentMapper.addComment(comment);
    }

    /**
     * 删除评论
     */
    @Override
    @Transactional
    public void delete(Integer id) {
        //查询并判断当前评论是否有子评论
        List<Comment> childrenList = commentMapper.getChildren(id);
        if(!childrenList.isEmpty()){
            //有，删除该评论的同时将该评论下的所有子评论删除（包含子中子）
            //创建并记录该评论的父子id集合
            ArrayList<Integer> ids = new ArrayList<>();
            ids.add(id);
            getChildrenIdList(ids,childrenList);
            //批量删除该评论链
            commentMapper.deleteBatch(ids);
            return;
        }
        //无，直接删除该条评论
        commentMapper.delete(id);

    }
    /**
     * 递归获取子评论id集合
     */
    private void getChildrenIdList(ArrayList<Integer> ids,List<Comment> childrenList){
        for (Comment comment : childrenList) {
            //获取该评论的子评论集合
            List<Comment> children = commentMapper.getChildren(comment.getId());
            if(!children.isEmpty()){
                //判断不为空时，递归
                ids.add(comment.getId());
                getChildrenIdList(ids,children);
            }else {
                //判断为空时，记录该条评论Id返回即可
                ids.add(comment.getId());
            }

        }
    }
    /**
     * 递归获取子评论(前端回显)
     */
    private void getChildren(List<CommentVO> commentVOList){
        for (CommentVO commentVO : commentVOList) {
            //查询当前根评论的子评论
            List<Comment> children = commentMapper.getChildren(commentVO.getId());
            List<CommentVO> children1 = getCommentVOList(children);
            //给children属性赋值
            commentVO.setChildren(children1);
            //判断为空结束本次循环进入下一次
            if(children1.isEmpty()){
                continue;
            }
            //递归查子
            getChildren(children1);
        }
    }
    /**
     * 将Comment类型集合转换成CommentVO类型集合
     * 并补充特殊数据
     */
    private List<CommentVO> getCommentVOList(List<Comment> commentList) {
        List<CommentVO> commentVOList = BeanUtil.copyToList(commentList, CommentVO.class);
        if(commentVOList.isEmpty()){
            return commentVOList;
        }
        //补充VO中独特的数据
        for (CommentVO commentVO : commentVOList) {
            if(commentVO.getPid() != -1){
                //设置回复目标评论的用户名（即toCommentUserId对应的用户名）
                commentVO.setToCommentUserName(userMapper
                        .findById(commentVO.getToCommentUserId())
                        .getName());
            }
            //设置评论人姓名（即create_by对应用户名）
            commentVO.setUsername(userMapper
                    .findById(commentVO.getCreateBy())
                    .getName());
        }
        return commentVOList;
    }

    /**
     * 将每一个CommentVO对象转换为TreeNode对象
     */
    private Function<CommentVO, TreeNode<Integer>> getNodeFunction() {
        return CommentVO -> {
            TreeNode<Integer> node = new TreeNode<>();
            node.setId(CommentVO.getId());
            node.setName(CommentVO.getUsername());
            node.setParentId(CommentVO.getPid());
            //补充树形节点的返回数据
            HashMap<String, Object> extra = new HashMap<>();
            extra.put(MessageConstant.COMMENT_CONTENT, CommentVO.getContent());
            extra.put(MessageConstant.TO_COMMENT_USER_ID, CommentVO.getToCommentUserId());
            extra.put(MessageConstant.TO_COMMENT_USER_NAME, CommentVO.getToCommentUserName());
            extra.put(MessageConstant.COMMENT_CREATE_TIME, CommentVO.getCreateTime());
            node.setExtra(extra);
            return node;
        };
    }
}
